package com.qzsoft.zhjd.materiel.modules.materielinventory.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qzsoft.jeemis.common.exception.RenException;
import com.qzsoft.system.modules.zhjdsysdept.entity.ZhjdSysDeptEntity;
import com.qzsoft.system.modules.zhjdsysdept.service.ZhjdSysDeptService;
import com.qzsoft.zhjd.common.annotation.ZhjdDataFilter;
import com.qzsoft.zhjd.common.components.BaseServiceComponent;
import com.qzsoft.zhjd.common.enums.BizCode;
import com.qzsoft.zhjd.common.excel.ZhjdExcelExportUtils;
import com.qzsoft.zhjd.common.excel.style.ZhjdExcelExportTemplateStyler;
import com.qzsoft.zhjd.common.utils.FunctionUtils;
import com.qzsoft.zhjd.common.utils.RenExceptionUtils;
import com.qzsoft.zhjd.materiel.modules.materielinventory.dto.MaterielInventoryImportDto;
import com.qzsoft.zhjd.materiel.modules.materielinventory.dto.MaterielInventoryListDto;
import com.qzsoft.zhjd.materiel.modules.materielinventory.entity.MaterielInventoryEntity;
import com.qzsoft.zhjd.materiel.modules.materielinventory.mapper.MaterielInventoryMapper;
import com.qzsoft.zhjd.materiel.modules.materielinventory.service.MaterielInventoryService;
import com.qzsoft.zhjd.materiel.modules.materielitem.dto.MaterielItemBaseSelectDto;
import com.qzsoft.zhjd.materiel.modules.materielitem.service.MaterielItemBaseService;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;

/**
 * @ClassName MaterielInventoryServiceImpl
 * @Description 物料盘点业务接口实现
 * @author linhuawei
 * @since 2022-03-28
 */
@Service
public class MaterielInventoryServiceImpl extends ServiceImpl<MaterielInventoryMapper, MaterielInventoryEntity>
        implements MaterielInventoryService {

    @Autowired
    private BaseServiceComponent baseServiceComponent;

    @Autowired
    private ZhjdSysDeptService zhjdSysDeptService;

    @Autowired
    private MaterielItemBaseService materielItemBaseService;

    @Override
    @ZhjdDataFilter(tableAlias = "t1")
    public IPage<MaterielInventoryListDto> pageDto(Map<String, Object> params) {
        IPage<MaterielInventoryListDto> page = baseServiceComponent.getPage(params, MaterielInventoryListDto.class);
        return baseMapper.queryDto(page, params);
    }

    @Override
    public boolean save(MaterielInventoryEntity entity) {
        checkEntity(entity);
        return super.save(entity);
    }

    @Override
    public boolean updateById(MaterielInventoryEntity entity) {
        checkEntity(entity);
        return super.updateById(entity);
    }

    @Override
    public void template(HttpServletResponse response) {
        List<MaterielInventoryImportDto> list = new ArrayList<MaterielInventoryImportDto>();
        String fileName = "养护基地材料盘点导入模板";
        ExportParams exportParams = new ExportParams(null, fileName);
        exportParams.setFixedTitle(false);
        exportParams.setStyle(ZhjdExcelExportTemplateStyler.class);

        try {
            ZhjdExcelExportUtils.exportExcel(response, fileName, exportParams, MaterielInventoryImportDto.class, list);
        } catch (Exception e) {
            log.error("养护基地材料盘点模板导出失败：{}", e);
            RenExceptionUtils.throwEx("数据导出失败");
        }
    }

    @Override
    public List<MaterielInventoryImportDto> importExcel(String baseCode, MultipartFile file) {
        // 判断基地是否存在
        ZhjdSysDeptEntity dept = zhjdSysDeptService.getBaseByCode(baseCode);
        if (null == dept) {
            RenExceptionUtils.throwEx(BizCode.PARAMS_ERROR, "基地不存在");
        }

        // 获取基地磅单材料列表
        List<MaterielItemBaseSelectDto> bindList = materielItemBaseService.getBind(baseCode);
        Set<String> bindSet = new HashSet<String>();
        for (MaterielItemBaseSelectDto dto : bindList) {
            bindSet.add(dto.getMaterielItemId());
        }

        // 解析excel文件
        List<MaterielInventoryImportDto> list = null;
        try {
            ImportParams params = new ImportParams();
            list = ExcelImportUtil.importExcel(file.getInputStream(), MaterielInventoryImportDto.class, params);
        } catch (Exception e) {
            log.error("养护基地材料盘点导入失败：{}", e);
            RenExceptionUtils.throwEx("养护基地材料盘点导入失败");
        }
        if (null == list || 0 == list.size()) {
            RenExceptionUtils.throwEx("养护基地材料盘点不存在");
        }

        // 数据校验
        List<MaterielInventoryEntity> entityList = new ArrayList<MaterielInventoryEntity>();
        MaterielInventoryEntity entity = new MaterielInventoryEntity();
        String str;
        String materielItemId;
        for (MaterielInventoryImportDto dto : list) {
            // 判断数据是否存在
            if (ObjectUtils.isEmpty(dto.getBeginTime())) {
                dto.setSuccess(false);
                dto.setErrorMesg("开始时间为空");
                continue;
            }
            if (ObjectUtils.isEmpty(dto.getEndTime())) {
                dto.setSuccess(false);
                dto.setErrorMesg("结束时间为空");
                continue;
            }
            if (ObjectUtils.isEmpty(dto.getMaterielItemName())) {
                dto.setSuccess(false);
                dto.setErrorMesg("材料名称为空");
                continue;
            }
            if (ObjectUtils.isEmpty(dto.getBeginBalance())) {
                dto.setSuccess(false);
                dto.setErrorMesg("期初库存为空");
                continue;
            }
            if (ObjectUtils.isEmpty(dto.getEndBalance())) {
                dto.setSuccess(false);
                dto.setErrorMesg("期末余额为空");
                continue;
            }

            // 判断材料是否存在
            str = dto.getMaterielItemName();
            if (ObjectUtils.isNotEmpty(dto.getMaterielItemSpec())) {
                str = str + dto.getMaterielItemSpec();
            }
            materielItemId = FunctionUtils.md5L32(str);
            if (!bindSet.contains(materielItemId)) {
                dto.setSuccess(false);
                dto.setErrorMesg("材料不存在");
                continue;
            }

            entity = new MaterielInventoryEntity();
            BeanUtils.copyProperties(dto, entity);
            entity.setBaseCode(baseCode);
            entity.setMaterielItemId(materielItemId);

            try {
                checkEntity(entity);
                entityList.add(entity);
                dto.setSuccess(true);
            } catch (RenException e) {
                dto.setSuccess(false);
                dto.setErrorMesg(e.getMessage());
            }
        }

        // 执行添加操作
        this.saveBatch(entityList, 100);

        // 返回导入结果
        return list;
    }

    /**
     * @Title checkEntity
     * @Description 校验数据对象
     * @param entity 需要校验的数据对象
     */
    private void checkEntity(MaterielInventoryEntity entity) {
        // 判断时间是否正确
        if (entity.getBeginTime().getTime() >= entity.getEndTime().getTime()) {
            RenExceptionUtils.throwEx(BizCode.PARAMS_ERROR, "开始时间不可晚与结束时间");
        }

        // 判断时间段是否交叉
        QueryWrapper<MaterielInventoryEntity> queryWrapper = new QueryWrapper<MaterielInventoryEntity>();
        queryWrapper.eq("base_code", entity.getBaseCode());
        queryWrapper.eq("materiel_item_id", entity.getMaterielItemId());
        if (null != entity.getId()) {
            queryWrapper.ne("id", entity.getId());
        }
        queryWrapper.and(timeQuery -> {
            timeQuery.between("begin_time", entity.getBeginTime(), entity.getEndTime());
            timeQuery.or();
            timeQuery.between("end_time", entity.getBeginTime(), entity.getEndTime());
            timeQuery.or(otherQuery -> {
                otherQuery.lt("begin_time", entity.getBeginTime())
                        .and(consumer -> consumer.gt("end_time", entity.getEndTime()));
            });

        });
        Integer count = baseMapper.selectCount(queryWrapper);
        if (null != count && 0 < count) {
            RenExceptionUtils.throwEx(BizCode.PARAMS_ERROR, "盘点时间有交叉，请重新设置盘点时间段");
        }

        // 本期收入
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("baseCode", entity.getBaseCode());
        params.put("materielItemId", entity.getMaterielItemId());
        params.put("startDate", entity.getBeginTime());
        params.put("endDate", entity.getEndTime());
        BigDecimal income = baseMapper.countIncome(params);

        // 本年累计收入数量
        Calendar cal = Calendar.getInstance();
        cal.setTime(entity.getEndTime());
        cal.set(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        params.put("startDate", cal.getTime());
        BigDecimal incomeYear = baseMapper.countIncome(params);
        entity.setIncome(income);
        entity.setIncomeYear(incomeYear);

        // 计算本期支出 = 期初 + 收入 - 期末
        BigDecimal expend = entity.getBeginBalance();
        if (null != income) {
            expend = expend.add(income);
        }
        expend = expend.subtract(entity.getEndBalance());
        if (0 < expend.compareTo(BigDecimal.ZERO)) {
            entity.setExpend(expend);
        }
    }

}
